package it.infodea.tapestrydea.components;

import it.infodea.tapestrydea.support.DeaEventConstants;
import it.infodea.tapestrydea.support.DeaUtils;
import it.infodea.tapestrydea.support.enumerations.CRUDMode;

import org.apache.tapestry5.Asset;
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.Block;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.RenderSupport;
import org.apache.tapestry5.annotations.Component;
import org.apache.tapestry5.annotations.Environmental;
import org.apache.tapestry5.annotations.IncludeStylesheet;
import org.apache.tapestry5.annotations.OnEvent;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.annotations.Path;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.annotations.SetupRender;
import org.apache.tapestry5.beaneditor.BeanModel;
import org.apache.tapestry5.corelib.components.ActionLink;
import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.services.ClientBehaviorSupport;
import org.apache.tapestry5.ioc.annotations.Inject;

/**
 * Componente "a tab" per visualizzare ed editare un elemento Identificable. Se
 * l'elemento è nullo o il suo idValue è nullo il componente si predisponde con
 * il tab edit aperto altrimenti per defualt visualizza il tab view. E'
 * possibile passare da una modalità all'altra (caricamento ajax del contenuto
 * dei tab) tramite gli appositi bottoni.
 * 
 * @author rob
 * 
 */

@IncludeStylesheet(value = "../assets/styles/tapestrydea.css")
public class BeanEditDisplayDea {

	/**
	 * The element to handle.
	 */
	@SuppressWarnings("unused")
	@Property
	@Parameter(required = true)
	private Object element;

	/**
	 * Set create or update to force the edit
	 */
	@Parameter
	private String forceEdit;

	/**
	 * A comma-separated list of property names to be retained from the
	 * {@link org.apache.tapestry5.beaneditor.BeanModel}. Only these properties
	 * will be retained, and the properties will also be reordered. The names
	 * are case-insensitive.
	 */
	@SuppressWarnings("unused")
	@Property(write = false)
	@Parameter(defaultPrefix = BindingConstants.LITERAL)
	private String include;

	/**
	 * A comma-separated list of property names to be removed from the
	 * {@link BeanModel}. The names are case-insensitive.
	 */
	@SuppressWarnings("unused")
	@Property(write = false)
	@Parameter(defaultPrefix = BindingConstants.LITERAL)
	private String exclude;

	/**
	 * Set true to hide the element. By default false
	 */
	@SuppressWarnings("unused")
	@Parameter(defaultPrefix = BindingConstants.LITERAL)
	@Property(write = false)
	private boolean hideElement = false;

	/**
	 * Set true to set only read mode. By default false
	 */
	@Parameter(defaultPrefix = BindingConstants.LITERAL)
	@Property(write = false)
	private boolean readMode = false;

	/**
	 * The label of the legend in the fieldset form. The field is adding only if
	 * the legendLabel is setted.
	 */
	@SuppressWarnings("unused")
	@Parameter(defaultPrefix = BindingConstants.LITERAL)
	@Property(write = false)
	private String legendLabel;

	/**
	 * The label of the header. The header is adding only if the headerLabel is
	 * setted.
	 */
	@SuppressWarnings("unused")
	@Parameter(defaultPrefix = BindingConstants.LITERAL)
	@Property(write = false)
	private String headerLabel;

	/**
	 * Block to show inside edit tab
	 */
	@SuppressWarnings("unused")
	@Parameter(value = "block:addEditBlock")
	@Property(write = false)
	private Block addEditBlock;

	/**
	 * Block to show below header (only in a display mode)
	 */
	@SuppressWarnings("unused")
	@Parameter(value = "block:addHeaderBlock")
	@Property(write = false)
	private Block addHeaderBlock;

	/**
	 * Block to show below header
	 */
	@SuppressWarnings("unused")
	@Parameter(value = "block:addMessageBlock")
	@Property(write = false)
	private Block addMessageBlock;
	
	/**
	 * Block to show inside header edit tab
	 */
	@SuppressWarnings("unused")
	@Parameter(value = "block:addHeaderEditBlock")
	@Property(write = false)
	private Block addHeaderEditBlock;

	/**
	 * Block to show inside display tab
	 */
	@SuppressWarnings("unused")
	@Parameter(value = "block:addDisplayBlock")
	@Property(write = false)
	private Block addDisplayBlock;

	/**
	 * Block to show external display tab
	 */
	@SuppressWarnings("unused")
	@Parameter(value = "block:addExtDisplayBlock")
	@Property(write = false)
	private Block addExtDisplayBlock;

	/**
	 * The text label for the edit button of the tab, by default "Edit".
	 */
	@SuppressWarnings("unused")
	@Parameter(value = "message:edit-label", defaultPrefix = BindingConstants.LITERAL)
	@Property(write = false)
	private String editLabel;

	/**
	 * The text label for the display button of the tab, by default "Display".
	 */
	@SuppressWarnings("unused")
	@Parameter(value = "message:display-label", defaultPrefix = BindingConstants.LITERAL)
	@Property(write = false)
	private String displayLabel;

	/**
	 * The text label for the submit button of the form, by default "Save".
	 */
	@SuppressWarnings("unused")
	@Parameter(value = "message:submit-label", defaultPrefix = BindingConstants.LITERAL)
	@Property(write = false)
	private String submitLabel;

	/**
	 * The text label for the cancel button of the form, by default "Cancel".
	 */
	@SuppressWarnings("unused")
	@Parameter(value = "message:cancel-label", defaultPrefix = BindingConstants.LITERAL)
	@Property(write = false)
	private String cancelLabel;

	/**
	 * Use to notification the text passed in this parameter
	 */
	@Parameter
	@Property(write = false)
	private String notification;

	@Inject
	private Block notificationMode;

	@Inject
	private Block displayMode;

	@Inject
	private Block editMode;

	@Inject
	private ComponentResources resources;

	@Inject
	@Path("classpath:/org/apache/tapestry5/ajax-loader.gif")
	private Asset loaderImage;

	@Environmental
	private ClientBehaviorSupport clientBehaviorSupport;

	@Environmental
	private RenderSupport renderSupport;

	@Component(id = "deaform")
	private BeanEditFormDea deaform;

	@SuppressWarnings("unused")
	@Component(parameters = { "context=prop:zone", "zone=prop:zone" })
	private ActionLink displayElement;

	@SuppressWarnings("unused")
	@Component(parameters = { "context=prop:zone", "zone=prop:zone" })
	private ActionLink editElement;

	@Property(write = false)
	private String zone;

	@SetupRender
	void setup() {
		if (!getHasErrors()) {
			resources.triggerEvent(DeaEventConstants.SETUP, null, null);
		}
	}

	void beginRender(MarkupWriter writer) {
		if (zone == null) {
			zone = renderSupport.allocateClientId(resources);
		}
		clientBehaviorSupport.addZone(zone, "show", "show");
		Element e = writer.element("div", "id", zone);
		e.addClassName("dea-bed-zone");
	}

	void afterRender(MarkupWriter writer) {
		writer.end();//div
	}

	@OnEvent(component = "displayElement")
	Object onView(String zone) {
		this.zone = zone;
		return displayMode;
	}

	@OnEvent(component = "editElement")
	Object onEdit(String zone) {
		this.zone = zone;
		return editMode;
	}

	@OnEvent(value = "failure", component = "deaform")
	void onFailure(Object element) {
		this.element = element;
	}

	/*PUBLIC*/
	public Object getInitialMode() {
		if (!DeaUtils.isEmpty(notification)) {
			return notificationMode;
		}
		if (!readMode && (getHasErrors() || !DeaUtils.isEmpty(forceEdit))) {
			return editMode;
		}
		return displayMode;
	}

	public boolean getHasErrors() {
		return deaform.getHasErrors();
	}

	public boolean isCreateMode() {
		return CRUDMode.CREATE.name().equals(forceEdit);
	}

	public String getLoaderImageUrl() {
		return loaderImage.toClientURL();
	}

}
